﻿#include "IpcClient.h"
#include <windows.h>
#include <cstring>
#include <thread>
#include "config/CConfig.h"

// win 自己定义了min和max，所以这里需要屏蔽掉
#ifdef min
#undef min
#endif

#include <algorithm>

IpcClient* IpcClient::g_IpcClient = nullptr;

bool IpcClient::Init(IpcClient *instance) {

    g_IpcClient = instance;
    if(!g_IpcClient->connect()){
        g_IpcClient->startServer();
        return false;
    }
    return true;
}

void IpcClient::Release() {
    if (g_IpcClient != nullptr) {
        g_IpcClient->disconnect();
        g_IpcClient = nullptr; 
    }  
}

bool IpcClient::GetCandidates(const wchar_t *input, int input_size, std::vector<std::wstring> &out_put) { // 静态方法，用于获取候选词（保持不变）
    if(g_IpcClient == nullptr) return false;
    return g_IpcClient->getCandidates(input,input_size, out_put);
}

bool IpcClient::SendLog(const std::wstring&& message) { // 静态方法，用于发送日志消息（保持不变）
    if(g_IpcClient == nullptr) return false;
    DWORD threadId = GetCurrentThreadId();
    return g_IpcClient->sendLog(L"Thread " + std::to_wstring(threadId) + L"| " + message) ;
}

bool IpcClient::OpenUI(){
    // if(CConfig::ServerDir.empty()){
    //     return false;
    // }

    // std::thread th([]() {
    //     ShellExecuteW(NULL, L"open", (CConfig::ServerDir + CONFIG_UI_EXE_NAME).c_str(),
    //                     NULL, CConfig::ServerDir.c_str(), SW_HIDE);
    // });
    // th.detach();
    if(g_IpcClient == nullptr) return false;
    return g_IpcClient->openUI();
}

IpcClient::IpcClient()
: _hPipe(INVALID_HANDLE_VALUE){
    _last_connect_time = 0;
}

bool IpcClient::IsReady(){
    return g_IpcClient != nullptr;
}

IpcClient::~IpcClient() {
    disconnect();
}

bool IpcClient::connect() {
    if (_hPipe != INVALID_HANDLE_VALUE) return true;
    
    _last_connect_time = time(NULL);
    _hPipe = CreateFileA(
        MENGYU_PIPE_NAME,
        GENERIC_READ |  // read and write access 
        GENERIC_WRITE, 
        0,              // no sharing 
        NULL,           // default security attributes
        OPEN_EXISTING,  // opens existing pipe 
        0,              // default attributes 
        NULL);          // no template file 

    if (_hPipe == INVALID_HANDLE_VALUE) 
        return false; 

    // The pipe connected; change to message-read mode. 
 
    DWORD dwMode = PIPE_READMODE_MESSAGE; 
    BOOL fSuccess = SetNamedPipeHandleState( 
      _hPipe,    // pipe handle 
      &dwMode,  // new pipe mode 
      NULL,     // don't set maximum bytes 
      NULL);    // don't set maximum time 

    if (!fSuccess) 
    {
      CloseHandle(_hPipe); 
      _hPipe = INVALID_HANDLE_VALUE;
      return false;
    } 

    
    return true;
}

void IpcClient::disconnect() {
    if (_hPipe != INVALID_HANDLE_VALUE) {
        CloseHandle(_hPipe);
        _hPipe = INVALID_HANDLE_VALUE;
    }
}

bool IpcClient::getCandidates(const wchar_t *input, int input_size,std::vector<std::wstring> &out_put) {
    if(input == NULL || input_size == 0){
        return false;
    }
    
    // 构造请求消息
    MengYuWubiPipeMsg* req = reinterpret_cast<MengYuWubiPipeMsg*>(_buffer);
    req->type = MengYuPipeMsgType::TYPE_INPUT;

    // 转换为UTF-8编码
    int u8_input_size = WideCharToMultiByte(CP_UTF8, 0, input, input_size, req->data, sizeof(_buffer)-sizeof(MengYuPipeMsgType), NULL, NULL);
    if(u8_input_size == 0){
        return false;
    }

    // 发送请求
    DWORD written;
    if(!sendBuffer(_buffer,sizeof(MengYuPipeMsgType) + u8_input_size, &written)){
        disconnect();
        return false;
    }

    // 读取响应（保持不变）
    DWORD read;
    if (!ReadFile(_hPipe, _buffer, sizeof(_buffer), &read, NULL)) {
        disconnect();
        return false;
    }

    // 解析响应数据
    MengYuWubiPipeMsg* resp = reinterpret_cast<MengYuWubiPipeMsg*>(_buffer);
    if (resp->type != MengYuPipeMsgType::TYPE_INPUT) return false;

    const char* ptr = resp->data;
    const char* end = _buffer + read;

    wchar_t wstr[256]; // 临时缓冲区，用于转换,由于每一项最大长度为255，所以这里设置为256，最后一位是'\0'
    while (ptr < end) {
        unsigned char len = *ptr++;
        if (ptr + len > end) break;

        // UTF-8转Unicode
        int wlen = MultiByteToWideChar(CP_UTF8, 0, ptr, len, wstr, sizeof(wstr)/sizeof(wstr[0]));
        if (wlen > 0) {
            out_put.emplace_back(wstr,wlen);
        }
        ptr += len;
    }

    return true;
}

bool IpcClient::sendLog(const std::wstring&& wmessage) {

    MengYuWubiPipeMsg* req = reinterpret_cast<MengYuWubiPipeMsg*>(_buffer);
    req->type = MengYuPipeMsgType::TYPE_LOG;

     // 转换为UTF-8编码
    int len = WideCharToMultiByte(CP_UTF8, 0, wmessage.c_str(), -1, req->data, sizeof(_buffer)-sizeof(MengYuPipeMsgType), NULL, NULL);
    
    if (len <= 0) return false;
    
    len += sizeof(MengYuWubiPipeMsg); //包括头

    DWORD written;
    if(!sendBuffer(_buffer, len, &written)){
        disconnect();
        return false;
    }

    // 接收服务端响应
    DWORD bytesRead;
    if (!ReadFile(_hPipe, _buffer, sizeof(_buffer), &bytesRead, NULL)) {
        disconnect();
        return false;
    }
    return true;
}

bool IpcClient::openUI() {
    MengYuWubiPipeMsg* req = reinterpret_cast<MengYuWubiPipeMsg*>(_buffer);
    req->type = MengYuPipeMsgType::TYPE_SHOWUI;
    DWORD written;

    if(!sendBuffer(_buffer, sizeof(MengYuWubiPipeMsg), &written)){
        disconnect();
        return false;
    }
   return true; 
}

void IpcClient::startServer(){
    if(_hPipe != INVALID_HANDLE_VALUE){
        return;
    }
    if(CConfig::ServerDir.empty()){
        return;
    }

    std::thread th([this]() {
        ShellExecuteW(NULL, L"open", (CConfig::ServerDir + CONFIG_SERVER_EXE_NAME).c_str(),
                        NULL, CConfig::ServerDir.c_str(), SW_HIDE);
    });
    th.detach();
}

bool IpcClient::sendBuffer(const void *data,int len,DWORD *written){
    
    if (_hPipe == INVALID_HANDLE_VALUE) {
        //连接
        if(_last_connect_time + 2 > time(NULL)){
            return false; // 2秒内不重复连接
        }

        if(!connect()){
            startServer();
            return false;
        }
    }

    //如果还是连不上，退出
    if(_hPipe == INVALID_HANDLE_VALUE){
        return false;
    }

    bool ret = WriteFile(_hPipe, data, len, written, NULL);
    if(!ret){
        //重新连接
        disconnect();
        if(!connect()){
            return false;
        }

        //再试一次
        ret = WriteFile(_hPipe, data, len, written, NULL);
    }

    return ret;
}